package com.example.codegen;

import com.example.utils.CJUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Optional;

import com.example.utils.Utils;
import org.apache.commons.cli.CommandLine;

public class CodeGenCJ {
    public static void main(String[] args) throws Exception {
        CJUtils.isVariableNameNormalized = true;//true 表示变量命名规格化，为class_n

        CommandLine cmd = Utils.parseCommandLineArgs(args);
        String inputDir = cmd.getOptionValue("input", "src/main/resources/list");
        String outputDir = cmd.getOptionValue("output", "src/main/resources/cj");

        if (!Utils.checkDirectoryExists(inputDir, "Input")) {
            System.exit(1);
        }
        if (!Utils.checkDirectoryExists(outputDir, "Output")) {
            System.exit(1);
        }

        System.out.println("Input Directory: " + inputDir);
        System.out.println("Output Directory: " + outputDir);
        String kLassPath = inputDir + "/MainClasses.txt";
        String dSLProgramPath = inputDir + "/dslProgram.txt";
        String dslInitPath = inputDir + "/";
        String outputMainPath = outputDir + "/main.cj";

        try {

            Type.disableInterface = false;
            CJUtils.inClass = true;
            BufferedWriter writer = new BufferedWriter(new FileWriter(outputMainPath));
            BufferedReader klassReader = new BufferedReader(new FileReader(kLassPath));
            BufferedReader dSLProgramReader = new BufferedReader(new FileReader(dSLProgramPath));
            writer.write("from std import collection.*\n\n");
            // test is klassReader is empty without readline
            Optional<Klass> klass = Optional.empty();
            do {
                klass = Parser.parserKlass(klassReader);
                if (klass.isPresent()) {
                    Klass k = klass.get();
                    writer.write(k.toCJ().replace('$', '_'));
                    writer.newLine();
                }
            } while (klass.isPresent());
            writer.write("func turnClass<T1, T2>(a: ?T1) :?T2 {\n" +
                    "        match (a) {\n" +
                    "        case Some(v) => v as T2\n" +
                    "        case None => Option<T2>.None\n" +
                    "    }\n" +
                    "}\n");
            writer.newLine();
            Type.disableInterface = true;

            // find all Main*.txt files expect MainClasses.txt in dslInitPath
            // for each file, generate a Main*.cj file under outputJavaDir using parserKlass
            String[] files = new java.io.File(dslInitPath).list();
            ArrayList<String> initFiles = new ArrayList<>();
            for (String file : files) {
                if (file.startsWith("Main") && file.endsWith(".txt") && !file.equals("MainClasses.txt")) {
                    initFiles.add(file);
                }
            }
            // sort the files by suffix index, zero first
            initFiles.sort((a, b) -> {
                int aIndex = Integer.parseInt(a.substring(4, a.length() - 4));
                int bIndex = Integer.parseInt(b.substring(4, b.length() - 4));
                return aIndex - bIndex;
            });
            Optional<Klass> klassInit = Optional.empty();
            for (String file : initFiles) {
                BufferedReader klassInitReader = new BufferedReader(new FileReader(dslInitPath + file));
                String outputInitPath = outputDir + "/" + file.replace(".txt", ".cj");
                BufferedWriter writer1 = new BufferedWriter(new FileWriter(outputInitPath));
                do {
                    klassInit = Parser.parserKlass(klassInitReader);
                    if (klassInit.isPresent()) {
                        Klass k = klassInit.get();
                        writer1.write(k.toCJ().replace('$', '_'));
                        writer1.newLine();
                    }
                } while (klassInit.isPresent());
                writer1.close();
                klassInitReader.close();
            }
            CJUtils.inClass = false;
            writer.newLine();
            Optional<Method> program = Optional.empty();
            do {
                program = Parser.parserMethod("", dSLProgramReader);
                if (program.isPresent()) {
                    Method m = program.get();
                    writer.write(m.toCJ().replace('$', '_'));
                    writer.newLine();
                }
            } while (program.isPresent());
            writer.newLine();
            writer.close();
            klassReader.close();
            dSLProgramReader.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
